package com.uobgroup.ews.uam.core.dao;

import java.util.List;

import javax.persistence.Query;

import org.springframework.stereotype.Repository;

import com.uobgroup.ews.uam.core.domain.Reference;
import com.uobgroup.ews.uam.core.domain.ReferenceType;
import com.uobgroup.ews.uam.core.domain.Segment;
import com.uobgroup.ews.uam.core.enums.ScopeType;

@Repository
public class ReferenceDaoImpl extends AbstractJpaDao<Reference> implements ReferenceDao {

   public ReferenceDaoImpl() {
      setClazz(Reference.class);
   }
   
   @SuppressWarnings("unchecked")
   @Override
   public List<Reference> findAllReferencesByType(ReferenceType referenceType) {
      Query query = entityManager.createNamedQuery(Reference.QUERY_FIND_REFERENCE_BY_TYPE);
      query.setParameter(Reference.PARAM_REFERENCE_TYPE, referenceType);
      List<Reference> references = query.getResultList();
      return references;
   }
   
   /**
    * @author dongn 
    */
   
   @SuppressWarnings("unchecked")
   @Override
   public Reference findReferencesByType(ReferenceType referenceType) {
      Query query = entityManager.createNamedQuery(Reference.QUERY_FIND_REFERENCE_BY_TYPE);
      query.setParameter(Reference.PARAM_REFERENCE_TYPE, referenceType);
      List<Reference> references = query.getResultList();
      if (references.isEmpty())
         return null;
      Reference reference = references.get(0);
      return reference;
   }
   
   @SuppressWarnings("unchecked")
   @Override
   public List<ReferenceType> findReferenceTypesThatHasReferencesByScope(ScopeType scope) {
      Query query = entityManager.createNamedQuery(Reference.QUERY_FIND_REFERENCE_THAT_HAS_REFERENCES_BY_SCOPE);
      query.setParameter(Reference.PARAM_SCOPE, scope);
      List<ReferenceType> results = (List<ReferenceType>) query.getResultList();
      return results;
   }
   
   @Override
   public long countReferencesByType(ReferenceType referenceType) {
      return entityManager.createNamedQuery(Reference.QUERY_COUNT_REFERENCE_BY_TYPE, Long.class)
            .setParameter(Reference.PARAM_REFERENCE_TYPE, referenceType).getSingleResult();
   }
   
   @SuppressWarnings("unchecked")
   @Override
   public List<Reference> findReferencesByType(ReferenceType referenceType, int firstResult, int maxResults) {
      Query query = entityManager.createNamedQuery(Reference.QUERY_FIND_REFERENCE_BY_TYPE);
      query.setParameter(Reference.PARAM_REFERENCE_TYPE, referenceType);
      query.setFirstResult(firstResult).setMaxResults(maxResults);
      List<Reference> results = (List<Reference>) query.getResultList();
      return results;
   }
   
   @SuppressWarnings("unchecked")
   @Override
   public Reference findReferenceThatHasCodeAndNotHasId(String code, Long id) {
      Query query = entityManager.createQuery("SELECT o FROM Reference o where lower(o.code) = :code AND o.id != :id",
            Reference.class);
      query.setParameter("code", code.toLowerCase());
      query.setParameter("id", id);
      List<Reference> references = query.getResultList();
      if (references.isEmpty())
         return null;
      Reference reference = references.get(0);
      return reference;
   }
   
   @SuppressWarnings("unchecked")
   @Override
   public Reference findReferenceThatHasNameAndNotHasId(String name, Long id) {
      Query query = entityManager.createQuery("SELECT o FROM Reference o where lower(o.name) = :name AND o.id != :id",
            Reference.class);
      query.setParameter("name", name.toLowerCase());
      query.setParameter("id", id);
      List<Reference> references = query.getResultList();
      if (references.isEmpty())
         return null;
      Reference reference = references.get(0);
      return reference;
   }
   
   @SuppressWarnings("unchecked")
   @Override
   public Reference findReferenceByIdAndScope(Long id, ScopeType scope) {
      Query query = entityManager.createQuery("SELECT o FROM Reference o where o.id = :id AND o.referenceType.scope = :scope",
            Reference.class);
      query.setParameter("id", id);
      query.setParameter("scope", scope);
      List<Reference> references = query.getResultList();
      if (references.isEmpty())
         return null;
      Reference reference = references.get(0);
      return reference;
   }
   
   @SuppressWarnings("unchecked")
   @Override
   public Reference findReferenceByCode(String code) {
      Query query = entityManager.createQuery("SELECT o FROM Reference o where lower(o.code) = :code",
            Reference.class);
      query.setParameter("code", code.toLowerCase());
      List<Reference> references = query.getResultList();
      if (references.isEmpty())
         return null;
      Reference reference = references.get(0);
      return reference;
   }
   
   @SuppressWarnings("unchecked")
   @Override
   public Reference findReferenceByName(String name) {
      Query query = entityManager.createQuery("SELECT o FROM Reference o where lower(o.name) = :name",
            Reference.class);
      query.setParameter("name", name.toLowerCase());
      List<Reference> references = query.getResultList();
      if (references.isEmpty())
         return null;
      Reference reference = references.get(0);
      return reference;
   }
   
   @Override
   public long countReferencesByReferenceTypeScope(ScopeType scope) {
      return entityManager.createNamedQuery(Reference.QUERY_COUNT_REFERENCE_BY_REFERENCE_TYPE_SCOPE, Long.class)
            .setParameter(Reference.PARAM_SCOPE, scope).getSingleResult();
   }   

   @SuppressWarnings("unchecked")
   @Override
   public List<Reference> findReferencesByReferenceTypeScope(ScopeType scope, int firstResult, int maxResults) {
      Query query = entityManager.createNamedQuery(Reference.QUERY_FIND_REFERENCES_BY_REFERENCE_TYPE_SCOPE);
      query.setParameter(Reference.PARAM_SCOPE, scope);
      query.setFirstResult(firstResult).setMaxResults(maxResults);
      List<Reference> results = (List<Reference>) query.getResultList();
      return results;
   }
   
   /**
    * END DONGN
    */
   @Override
   public long count() {
      return entityManager.createQuery("SELECT COUNT(o) FROM Reference o", Long.class).getSingleResult();
   }

   @Override
   public List<Reference> findAll(int firstResult, int maxResults) {
      return entityManager.createQuery("SELECT o FROM Reference o", Reference.class).setFirstResult(firstResult)
            .setMaxResults(maxResults).getResultList();
   }

   
   @SuppressWarnings("unchecked")
   @Override
   public List<Reference> findAllReferencesThatHasNoSegment(ReferenceType segmentType) {
      Query query = entityManager.createNamedQuery(Reference.QUERY_FIND_REFERENCES_THAT_HAS_NO_SEGMENT);
      query.setParameter(Reference.PARAM_REFERENCE_TYPE, segmentType);
      List<Reference> results = (List<Reference>) query.getResultList();
      return results;
   }

   //CAN KHOI PHUC 
   /*@SuppressWarnings("unchecked")
   @Override
   public List<Reference> findReferencesByType(ReferenceType processingCenter) {
      Query query = entityManager.createNamedQuery(Reference.QUERY_FIND_REFERENCE_BY_TYPE);
      query.setParameter(Reference.PARAM_REFERENCE_TYPE, processingCenter);
      List<Reference> results = (List<Reference>) query.getResultList();
      return results;
   }*/
   
   

   @SuppressWarnings("unchecked")
   @Override
   public Segment findSegment(Long id) {
      Query query = entityManager.createNamedQuery(Segment.QUERY_FIND_SEGMENT_BY_ID);
      query.setParameter(Segment.PARAM_SEGMENT_ID, id);
      List<Segment> results = (List<Segment>) query.getResultList();
      return results.get(0);
   }

   @Override
   public List<Segment> findSegmentEntries(int firstResult, int maxResults) {
      return entityManager.createQuery("SELECT s FROM Segment s", Segment.class).setFirstResult(firstResult)
            .setMaxResults(maxResults).getResultList();
   }

   @Override
   public float countSegments() {
      return entityManager.createQuery("SELECT COUNT(s) FROM Segment s", Long.class).getSingleResult();
   }

   @Override
   public List<Segment> findAllSegments() {
      return entityManager.createQuery("SELECT s FROM Segment s", Segment.class).getResultList();
   }

   @Override
   public void removeSegment(Segment segment) {
      Query query = entityManager.createQuery("DELETE Segment s WHERE s.id = :segmentId");
      query.setParameter("segmentId", segment.getId());
      query.executeUpdate();
   }

   @SuppressWarnings("unchecked")
   @Override
   public List<Reference> findSegmentReferencesByName(String name) {
      String queryStr = "select r from Reference r where r.id in (select s.segmentReference.id from Segment s) and lower(r.name) like :segmentName";
      Query query = entityManager.createQuery(queryStr);
      query.setParameter("segmentName", "%" + name.toLowerCase() + "%");
      return query.getResultList();
   }

   /* 
    * Phuong Tran
    */
   @SuppressWarnings("unchecked")
   @Override
   public Segment findSegmentByRefId(Long id) {
      String queryStr = "select seg from Segment seg where seg.segmentReference.id = :id";
      Query query = entityManager.createQuery(queryStr, Segment.class);
      query.setParameter("id", id);
      List<Segment> results = (List<Segment>) query.getResultList();
      return results.get(0);
   }

   @Override
   public void addSegment(Segment segment) {
      entityManager.persist(segment);
   }

   @Override
   public long countSegmentsThatHasSegmentReference(Reference segment) {
      return entityManager.createQuery("SELECT COUNT(S) FROM Segment S WHERE S.segmentReference = :segmentReference", Long.class)
            .setParameter("segmentReference", segment).getSingleResult();
   }
}
